#include <QFile>
#include "Game.h"

BaseGameObject* Game::sBaseGameObjects[Const::GAME_BOARD_GRID_COUNT_V][Const::GAME_BOARD_GRID_COUNT_H];

/**
 * 构造方法。
 * @param bitmap    后台缓冲位图
 * @param gameBoard 游戏区域
 */
Game::Game(QPixmap* bitmap, QWidget* gameBoard) :
    mBitmap(bitmap),
    mBoxCount(0),
    mGameBoard(gameBoard),
    mLevel(1),
    mMan(nullptr),
    mMoveCount(0),
    mStatus(END) {
    // 进入第1关
    this->enterLevel();
}

/**
 * 析构方法。
 */
Game::~Game() {
    this->clear();
}

/**
 * 清除所有对象。
 */
void Game::clear() {
    // 删除所有游戏物体
    for (int i = 0; i < Const::GAME_BOARD_GRID_COUNT_V; i++) {
        for (int j = 0; j < Const::GAME_BOARD_GRID_COUNT_H; j++) {
            if (sBaseGameObjects[i][j] != nullptr) {
                delete sBaseGameObjects[i][j];
            }
        }
    }
    memset(sBaseGameObjects, 0, sizeof(sBaseGameObjects));

    // 删除所有移动结点
    QListIterator<MoveNode*> iterator(mMoveList);
    while (iterator.hasNext()) {
        delete iterator.next();
    }
    mMoveList.clear();
}

/**
 * 进入关卡。
 */
void Game::enterLevel() {
    // 重绘游戏区域
    mDrawer.begin(mBitmap);
    mDrawer.fillRect(0, 0, Const::GAME_BOARD_WIDTH, Const::GAME_BOARD_HEIGHT, Const::GAME_BOARD_COLOR);
    mDrawer.end();

    // 删除所有物体
    this->clear();

    // 读取关卡文件
    QFile levelFile(QString(Const::LEVEL_FILE_PATH).arg(mLevel));
    levelFile.open(QIODevice::ReadOnly | QIODevice::Text);

    // 创建所有物体
    int read = 1;
    char buffer = 0;
    BaseGameObject::Type type;
    mBoxCount = 0;
    for (int y = 0; y < Const::GAME_BOARD_GRID_COUNT_V; y++) {
        for (int x = 0; x < Const::GAME_BOARD_GRID_COUNT_H; x++) {
            levelFile.read(&buffer, 1);
            if (read == 0) {
                continue;
            }
            if (buffer == '\r' || buffer == '\n') {
                x--;
                continue;
            }

            type = static_cast<BaseGameObject::Type>(atoi(&buffer));

            // 创建箱子
            if (type == BaseGameObject::BOX) {
                sBaseGameObjects[y][x] = new Box(new BaseGameObject(mBitmap, BaseGameObject::BACKGROUND, x, y), mBitmap, type, x, y);
                mBoxCount++;
                continue;
            }

            // 创建小人
            if (type == BaseGameObject::MAN) {
                sBaseGameObjects[y][x] = mMan = new Man(new BaseGameObject(mBitmap, BaseGameObject::BACKGROUND, x, y), mBitmap, mGameBoard, type, x, y);
                continue;
            }

            // 创建背景、目的地、墙
            sBaseGameObjects[y][x] = new BaseGameObject(mBitmap, type, x, y);
        }
    }

    // 关闭文件
    levelFile.close();

    // 重置成员变量
    mMoveCount = 0;
    mStatus = PLAYING;

    // 发送通知
    emit UM_GOTO_LEVEL(mLevel);
}

/**
 * 游戏结束。
 * @param allOver   全部通关则为 true，否则为 false
 */
void Game::gameOver(bool allOver) {
    // 将状态设置为已结束
    mStatus = END;

    // 发送通知
    emit UM_GAME_OVER(allOver);
}

/**
 * 获取当前关卡数。
 * @return 当前关卡数
 */
int Game::getLevel() {
    return mLevel;
}

/**
 * 进入指定的关卡。
 * @param level    关卡数
 */
void Game::gotoLevel(int level) {
    if (level <= Const::LEVEL_COUNT) {
        mLevel = level;
        enterLevel();
    }
}

/**
 * 进入下一关。
 */
void Game::gotoNextLevel() {
    if (mLevel < Const::LEVEL_COUNT) {
        mLevel++;
        enterLevel();
    }
}

/**
 * 判断是否胜利。
 * @return 胜利则返回 true，否则返回 false
 */
bool Game::isWon() {
    return mBoxCount == 0;
}

/**
 * 按键事件的响应方法。
 * @param key  按键
 */
void Game::onKeyPressed(int key) {
    // 如果没在玩，则直接返回
    if (mStatus != PLAYING) {
        return;
    }

    // 如果按的不是方向键，则直接返回
    if (key < Qt::Key_Left || key > Qt::Key_Down) {
        return;
    }

    // 移动小人。如果不能移动，则直接返回
    BaseGameObject::MoveResult moveResult = BaseGameObject::CANNOT_MOVE;
    BaseGameObject* movedBox = mMan->move(key, &moveResult);
    if (moveResult == BaseGameObject::NO_MOVE) {
        return;
    }

    // 重绘游戏区域
    mGameBoard->update();

    // 增加移动次数
    mMoveCount++;

    // 发送通知
    emit UM_MAN_MOVED(mMoveCount);

    // 判断是否胜利
    if (moveResult == BaseGameObject::ARRIVED_ON_DEST) {
        mBoxCount--;
        if (this->isWon()) {
            bool allOver = mLevel == Const::LEVEL_COUNT;
            this->gameOver(allOver);
            if (!allOver) {
                this->gotoNextLevel();
            }
            return;
        }
    } else if (moveResult == BaseGameObject::LEFT_FROM_DEST) {
        mBoxCount++;
    }

    // 将本次移动加入列表
    mMoveList.append(new MoveNode(movedBox, key));
}

/**
 * 重玩本关。
 */
void Game::restart() {
    this->gotoLevel(mLevel);
}

/**
 * 回退，即撤消上一次操作。
 */
void Game::undo() {
    if (mMoveCount == 0) {
        return;
    }

    // 计算方向（方向与最后一次移动的方向相反）
    int direction = 0;
    MoveNode* moveListNode = mMoveList.last();
    switch (moveListNode->getDirection()) {
        case Qt::Key_Down:
            direction = Qt::Key_Up;
            break;
        case Qt::Key_Left:
            direction = Qt::Key_Right;
            break;
        case Qt::Key_Right:
            direction = Qt::Key_Left;
            break;
        case Qt::Key_Up:
            direction = Qt::Key_Down;
            break;
    }

    // 移动小人
    BaseGameObject::MoveResult moveResult = BaseGameObject::CANNOT_MOVE;
    mMan->move(direction, &moveResult);

    // 移动箱子
    BaseGameObject* box = moveListNode->getBox();
    box->move(direction, &moveResult);
    if (moveResult == BaseGameObject::LEFT_FROM_DEST) {
        mBoxCount++;
    } else if (moveResult == BaseGameObject::ARRIVED_ON_DEST) {
        mBoxCount--;
    }

    // 删除当前的移动结点
    mMoveList.removeLast();
    delete moveListNode;

    // 发送通知
    mMoveCount--;
    emit UM_MAN_MOVED(mMoveCount);
}
